home *** CD-ROM | disk | FTP | other *** search
/ Total Network Tools 2002 / NextStepPublishing-TotalNetworkTools2002-Win95.iso / Archive / Misc Servers / Zope.exe / BEFORETRAVERSE.PY < prev    next >
Encoding:
Python Source  |  2000-06-09  |  3.6 KB  |  114 lines

  1. """BeforeTraverse interface and helper classes"""
  2.  
  3. # Interface
  4.  
  5. def registerBeforeTraverse(container, object, app_handle, priority=99):
  6.     """Register an object to be called before a container is traversed.
  7.  
  8.     'app_handle' should be a string or other hashable value that
  9.     distinguishes the application of this object, and which must
  10.     be used in order to unregister the object.
  11.  
  12.     If the container will be pickled, the object must be a callable class
  13.     instance, not a function or method.
  14.  
  15.     'priority' is optional, and determines the relative order in which
  16.     registered objects will be called.
  17.     """
  18.     btr = getattr(container, '__before_traverse__', {})
  19.     btr[(priority, app_handle)] = object
  20.     rewriteBeforeTraverse(container, btr)
  21.  
  22. def unregisterBeforeTraverse(container, app_handle):
  23.     """Unregister a __before_traverse__ hook object, given its 'app_handle'.
  24.  
  25.     Returns a list of unregistered objects."""
  26.     btr = getattr(container, '__before_traverse__', {})
  27.     objects = []
  28.     for k in btr.keys():
  29.         if k[1] == app_handle:
  30.             objects.append(btr[k])
  31.             del btr[k]
  32.     if objects:
  33.         rewriteBeforeTraverse(container, btr)
  34.     return objects
  35.  
  36. def queryBeforeTraverse(container, app_handle):
  37.     """Find __before_traverse__ hook objects, given an 'app_handle'.
  38.  
  39.     Returns a list of (priority, object) pairs."""
  40.     btr = getattr(container, '__before_traverse__', {})
  41.     objects = []
  42.     for k in btr.keys():
  43.         if k[1] == app_handle:
  44.             objects.append((k[0], btr[k]))
  45.     return objects
  46.  
  47. # Implementation tools
  48.  
  49. def rewriteBeforeTraverse(container, btr):
  50.     """Rewrite the list of __before_traverse__ hook objects"""
  51.     container.__before_traverse__ = btr
  52.     hookname = '__before_publishing_traverse__'
  53.     dic = hasattr(container.__class__, hookname)
  54.     bpth = container.__dict__.get(hookname, None)
  55.     if isinstance(bpth, MultiHook):
  56.         bpth = bpth._prior
  57.     bpth = MultiHook(hookname, bpth, dic)
  58.     setattr(container, hookname, bpth)
  59.     
  60.     keys = btr.keys()
  61.     keys.sort()
  62.     for key in keys:
  63.         bpth.add(btr[key])
  64.  
  65. class MultiHook:
  66.     """Class used to multiplex hook.
  67.  
  68.     MultiHook calls the named hook from the class of the container, then
  69.     the prior hook, then all the hooks in its list.
  70.     """
  71.     def __init__(self, hookname, prior, defined_in_class):
  72.         self._hookname = hookname
  73.         self._prior = prior
  74.         self._defined_in_class = defined_in_class
  75.         self._list = []
  76.  
  77.     def __call__(self, container, request):
  78.         if self._defined_in_class:
  79.             # Assume it's an unbound method
  80.             getattr(container.__class__, self._hookname)(container, request)
  81.         prior = self._prior
  82.         if prior is not None:
  83.             prior(container, request)
  84.         for cob in self._list:
  85.             cob(container, request)
  86.  
  87.     def add(self, cob):
  88.         self._list.append(cob)
  89.  
  90. # Helper class
  91.  
  92. class NameCaller:
  93.     """Class used to proxy sibling objects by name.
  94.  
  95.     When called with a container and request object, it gets the named
  96.     attribute from the container and calls it.  If the name is not
  97.     found, it fails silently.
  98.  
  99.     >>> registerBeforeTraverse(folder, NameCaller('preop'), 'XApp')
  100.     """
  101.  
  102.     def __init__(self, name):
  103.         self.name = name
  104.  
  105.     def __call__(self, container, request):
  106.         try:
  107.             meth = getattr(container, self.name)
  108.         except AttributeError:
  109.             return
  110.  
  111.         args = getattr(getattr(meth, 'func_code', None), 'co_argcount', 2)
  112.         apply(meth, (container, request, None)[:args])
  113.     
  114.